; Grange Murder print routines.
;
 begin
cif debugmode
code -
 prs "*****AAPRINT*****"
code +
cend
;
; Routines to output a list of words, adding appropriate punctuation. 
; Output is delayed, presumably because we don't know what punctuation 
; is needed until after deciding to print an item, e.g consider the 
; difficulty of printing 'and' before the last entry in a list. They 
; only seem to be used when listing objects and exits (see code above).
;
.OUTWORDNONE ; flush any buffered words
 WORD1=0
 WORD2=0
;
.OUTWORD12
 WORD3=0
 WORD4=0
;
.OUTWORD1234
; BEFORE CALLING, SET OUTPUTWORD=0. AT THE END OF THE LIST, CALL THIS 
; ROUTINE WITH X1=0 AND THE LIST WILL BE FINISHED OFF WITH A FULL STOP.
 IF WORD1=0 THEN @OWEND
; FIRST OR SECOND WORD - JUST ADD TO BUFFER
 add wordsoutput,c1
 X4=OUTPUTWORD
 VALUE=WORD1
 GOSUB @WRITEOUTBUFFER
 VALUE=WORD2
 GOSUB @WRITEOUTBUFFER
 VALUE=WORD3
 GOSUB @WRITEOUTBUFFER
 VALUE=WORD4
 GOSUB @WRITEOUTBUFFER
 OUTPUTWORD=X4
 IF OUTPUTWORD<>24 THEN @OWRET
;
; THIRD TO SUBSEQUENT WORDS - print out oldest word
; in buffer, and shift the other two down
 X4=0 ; index into OUTPUTBUFFER
 GOSUB @OWPRINT
 X1=0
 X2=8
.OW2
 X3=OUTPUTBUFFER(X2)
 OUTPUTBUFFER(X1)=X3
 ADD X1,C1
 ADD X2,C1
 IF X1<16 THEN OW2
code -
 MESSAGE COMMA
code +
 OUTPUTWORD=16
.OWRET
 RETURN
;
.OWEND
; HAVE RECEIVED THE TERMINATOR
 wordsoutput=1
 IF OUTPUTWORD=0 THEN OWRET ; NO WORDS OUTPUT AT ALL
; THERE MUST BE AT LEAST ONE WORD REMAINING IN BUFFER - SO OUTPUT IT
 X4=0 ; index into OUTPUTBUFFER
 GOSUB OWPRINT
 IF OUTPUTWORD=8 THEN OWSTOP ; ONLY ONE WORD OUTPUT - SO THATS IT !
; MUST HAVE OUTPUTWORD=2, SO 2 OR MORE WORDS OUTPUT.
; THEREFORE WANT TO FINISH OFF WITH 'AND'
code -
 MESSAGE SPACEAND
code +
 X4=8 ; index into OUTPUTBUFFER
 GOSUB OWPRINT
.OWSTOP
 OUTPUTWORD=0
code -
 MESSAGE DOT
code +
 RETURN
;---
.OWPRINT
; Print words by message number starting at outputbuffer(X4)
 X3=3 ; words to print
.OWPRINT1
 GOSUB READOUTBUFFER
 X1=VALUE
 IF OWTYPE=OWOBJECTS THEN @printANobjectX1
code -
 MESSAGE VALUE
code +
 SUB X3,C1
 IF X3<NEGATIVE THEN OWPRINT1
 RETURN
;---
.WRITEOUTBUFFER
; write 16 bit word VALUE to OUTPUTBUFFER at (X4)
; do 16 bit autoincrement after the write
; must preserve X3
 ADD X4,C1 ; write low byte first
 OUTPUTBUFFER(X4)=VALUE
 SUB X4,C1
 GOSUB @VALUEDIV256
 OUTPUTBUFFER(X4)=VALUE
 ADD X4,C2 ; skip on to next entry
 RETURN
;---
.READOUTBUFFER
; read 16 bit word VALUE from OUTPUTBUFFER(X4)
; do 16 bit autoincrement after the read
 VALUE=OUTPUTBUFFER(X4)
 GOSUB @VALUETIMES256
 ADD X4,C1
 X1=OUTPUTBUFFER(X4)
 ADD VALUE,X1
 ADD X4,C1 ; skip on to next entry
 RETURN
;---
.VALUEDIV256
; divide VALUE by 256
; must preserve X4
 X1=0
 X2=256
.VD256
 SUB VALUE,X2
 IF VALUE>NEGATIVE THEN VDEND
 ADD X1,C1
 GOTO VD256

.VDEND
 VALUE=X1
 RETURN
;---
.printACTORactionDOT
; print action done by actor: verb noun1 prep noun2
 gosub printACTORaction
 goto @printdot

.printACTORaction
code -
 message cr
code +
 gosub printACTORverb
 object=noun1
 gosub @printTHEobject2

; now prep/noun2, if specified
 if noun2=nullobject then daend
 if prep=0 then pa1
 gosub printPREP
.pa1
 object=noun2
 gosub @printTHEobject2

.daend
.daaret
 return
;---
.printPREP
 m1printsave=m1
 m1=prepoffset
 add m1,prep
 goto @printM1andrestoreM1
;---
;.printANobjectVERB
; x1=object ; ( the character doing the action)
; gosub @printANobjectX1
; goto printverb
;---
;.printactorverbdot
; gosub printactorverb
; goto @printdot
;---
.printACTORverb
 gosub printACTOR
 if verb<>iam then printverb
 m1=132 ; was
 if actor=user then @printm1
 goto printverb
;---
.printACTOR
 x1=actor
 goto @printTHEobjectx1
;---
.printOBJECTverb
 gosub @printTHEobject ; character doing the action
; drop through to printverb...

.printVERB
 x1=verb
 m1printsave=m1
 if verb<>iam then printverbNoEnding

.pvam
 x1=object
 gosub @conjugatex1
 m1=133 ; were
 if result=pluralsome then @printm1

.printverbnoending
 m1=verboffset
 add m1,verb
 goto @printM1
;---
.CONJUGATEX1
; depending on the object represented by x1
; return result=ita,itan,singularsome,he,she,pluralsome, you or the
; x1 preserved, x2 corrupted
 result=0
 if x1>maxobject then conjret
 result=x1 ; preserve x1
 add x1,x1
 x1=objectstart(x1)
; now extract bits 4:6

 asr x1
 asr x1
 asr x1
 asr x1
 x2=7
 and x1,x2

;; x2=16
;; gosub @x1divx2
;; x2=8
;; gosub @x1modx2

 x2=result ; restore object number (saved in result, above)
 gosub @SpecialConjugate

 result=x1 ; set up result for return to caller
 x1=x2 ; restore x1 (i.e. object number)
; now result contains one of the following values:
; 0=ita
; 1=itan
; 2=singularsome
; 3=he
; 4=she
; 5=pluralsome
; 6=you
.conjret
 RETURN
;---
.printANobjectX1 ; for object 'X1', print a object or an object
 if wanttoprintand=false then daonotand
 goto @printAND ; link onto a previous message

.daonotand
 GOSUB @CONJUGATEX1
 if result<>itan then descnan
 m1=22 ; an
 gosub @printM1
 goto doobj
.descnan
 if result>she then doobj ;>>mike 1/2/88
 if result=singularSome then doobj ;>>mike 8/5/88
 M1=20 ; a_
 gosub @printM1
.DOOBJ
 GOTO @DESCOBJX1
;---
; Print object;  as in 'You can't see SAM' or 'You can't see HIM'
.printTHEobject2
 if wanttoprintand=false then dto2notand
 goto @printAND ; link onto a previous message

.dto2notand
 if object>254 then @printthat ; fail-safe code - assumes nullobject=255
 x1=object
; PRINT OUT 'THE <desc>'
; Also, print 'it' if possible
 GOSUB @CONJUGATEX1
; because e.g. 'some takes the object' looks silly
 IF LASTWORDPRINTED<>X1 THEN @DTOXTHE
 m2=570
; bug fix by graham 16/10/88. see message group 2430 for full details
 if actor<>object then pto2notitself
 m2=2430
.pto2notitself
 add m2,result ; it,some etc.
 goto @printM2
;---
.printTHEobject
 x1=object
;
.printTHEobjectx1 ; PRINT OUT 'the <desc>', using 'it' if possible
 if wanttoprintand=false then dtonotand
 goto @printAND ; link onto a previous message

.dtonotand
 if x1>254 then @printthat ; fail-safe code - assumes nullobject=255
 GOSUB @CONJUGATEX1
 IF RESULT=2 THEN dtoxthe ; prevent some
; because e.g. 'some takes the object' looks silly
 IF LASTWORDPRINTED<>X1 THEN DTOXTHE

.dtoprintarticle
 wanttoprintand=false
 m2=560
 add m2,result ; it,some etc.
 goto @printM2

.DTOXTHE
 if result=pluralsome then dtosome
 if result>she then descobjx1 ; some,you, proper he, prop she have no "the"

.dtosome
 M2=THE ; because e.g. 'the you' looks pretty daft
 gosub @printM2
 goto do2 ; prevent 'the some'
;---
.DESCOBJX1
 if result=singularsome then dosome
 if result<>pluralsome then do2

.dosome
 gosub @printSOME

.do2
 LASTWORDPRINTED=X1
 gosub @conjugatex1
 x1=lastwordprinted ; restore object no. from just above

 m2=OBJECTDESCBASE
 ADD m2,X1
 gosub @printM2

.DESCOBJRET
 RETURN
;---
; Print 'That', using standard routines..
;.printTHATdot
; gosub printthat
; goto printdot
;
.printTHAT
 m1printsave=m1
 m1=2046 ; 'that'
 goto printM1andrestoreM1
;
.printSOME
 m1printsave=m1
 m1=some ; 'that'
 goto printM1andrestoreM1
;---
; Double message output routines (a pair of messages with a parameter)..
;
;.printM1theobjectx1NEXTdot ; e.g 'Unfortunately, the X1 is too high up.'
; gosub printM1
; gosub @printTHEobjectx1
; add m1,c1
; goto printM1dot
;---
; Standard message output routines...
;
;.ActorM1Dot
; gosub @PrintActor
; goto PrintM1Dot
;
.printM1dot
 gosub printM1
;
.printDOT
 wanttoprintand=false
 m1printsave=m1
 m1=dot
 goto printM1andrestoreM1
;---
.printAND
 wanttoprintand=false; don't need another 'and'
 m1printsave=m1
 m1=and
 goto printM1andrestoreM1
;---
.printM2
 m1printsave=m1
 m1=m2
 goto @printM1andrestoreM1
;---
.printM1andrestoreM1
 gosub printM1
 m1=m1printsave
 return
;
.printM1
; print message m1 to user(s) if at ROOM
; must not alter RESULT or PROCESSED!
 if forceprinting=true then printM1go
 if currentuserroom<>room then @printM1ret
;
;.forcem1
;
;; if m1<30000 then printm1go
;; if m1>31000 then printm1go
;;code -
;; prs "["
;; print m1
;; prs "] "
;;code +
;
.printM1go
code -
 message m1
code +
;
;=====
; Intercept evidence messages
push x1
push x2
push x3
push x4
push x5
 &x1=list4(26) ; evidence message table
 x2=murder
 sub x2,c1 ; x2 is murder 0 to 8
 add x2,x2 ; table pointers are words
 add x1,x2
 &x1=list4(x1) ; x1 points to evidence message table for this murder
.ism1evidence
 &x2=list4(x1) ; x2 is search message
 if x2=0 then @evidencemessret ; end of table
 add x1,c2
 if x2=m1 then m1isevidence ; found a match
;
; match not found, so move on to next entry in the table
;.findendofentry
 add x1,c2 ; move pointer to score value
 &x2=list4(x1) ; x2 is score value
 add x1,c2
 if x2<20 then ism1evidence ; normal score value - reached end of entry
; special score value - skip paired message
 add x1,c2
 goto ism1evidence
;
; we've found a match! m1 is treated as evidence
.m1isevidence
 &x3=list4(x1) ; x3 is corresponding note message
 add x1,c2
 &x4=list4(x1) ; x4 is score value for this evidence
 add x1,c2
 x5=0 ; null paired message
 if x4<>255 then nopairedmessage ; normal score value - no paired messages
;
; Evidence is only valid if certain paired messages have already 
; been noted. Although at this stage, we cannot disregard any evidence 
; if the paired message has not been noted, since it may well be noted 
; at a later time.
 &x5=list4(x1) ; get the offset to a list of paired messages
 add x1,c2
;
.nopairedmessage
 gosub storeevidence
;
.evidencemessret
pop x5
pop x4
pop x3
pop x2
pop x1
;=====
;
.printm1ret
 return
;
;=====
; Store evidence note in buffer.
; x3 is the note
; x4 is the score value
; x5 is the paired message (if score value is specially coded)
.storeevidence
 gosub @shuntEbuffer ; make room in buffer for new entry
push x1
 &x1=list4(30) ; x1 points to start of evidence buffer
 &list4(x1)=x3 ; write note
 add x1,c2
 &list4(x1)=x4 ; write score value
 add x1,c2
 &list4(x1)=x5 ; write paired message
pop x1
 return
;---
; shunt up all entries in evidence buffer, either to make way 
; for a new entry or to scrap old entries after a period of 
; time.
.ShuntEBuffer
push x1
push x2
push x3
push x4
 &x1=list4(30) ; x1 points to start of evidence buffer
 x2=58 ; buffer is 30 words long
 add x2,x1 ; x2 points to last entry in buffer
 x3=52
 add x3,x1 ; x3 points to penultimate entry in buffer
.ShuntWord
 if x3<x1 then ShuntedOk ; shunted to start of table
 &x4=list4(x3) ; get lower entry
 &list4(x2)=x4 ; move to upper entry
 sub x2,c2
 sub x3,c2 ; move down the buffer
 goto ShuntWord ; shunt the next word
;
; Buffer has been shunted up, so zero the first entry
.ShuntedOk
 &list4(x1)=c0
 add x1,c2
 &list4(x1)=c0
 add x1,c2
 &list4(x1)=c0
pop x4
pop x3
pop x2
pop x1
 return
;=====
;
;---
; Output one of 'ALTERNATIVES' messages, starting at 'M1'
.VARYMESSAGEDOT
 GOSUB VARYMESSAGE
 GOTO @printDOT
;
.VARYMESSAGE
 M1printSAVE=M1
 GOSUB GETVARYM1
 goto @printM1andrestoreM1
;
; Add number between 0 and ALTERNATIVES-1 to M1
.GETVARYM1
 ADD CURRENTMESSAGE,C1
 IF CURRENTMESSAGE<ALTERNATIVES THEN VMOK
 CURRENTMESSAGE=0
.VMOK
 ADD M1,CURRENTMESSAGE
 RETURN
